import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, Method } from "axios";
interface resType<T> {
  data: T;
  flag: number;
}
interface HFInstanceInterceptors<T = AxiosResponse> {
  requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig;
  requestInterceptorCatch?: (err: any) => any;
  responseInterceptor?: (res: T) => any;
  responseInterceptorCatch?: (err: any) => any;
}

interface HFRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: HFInstanceInterceptors<resType<T>>;
}

class HFRequest {
  instance: AxiosInstance;

  constructor(config: HFRequestConfig) {
    this.instance = axios.create(config);

    // 全局的拦截器
    this.instance.interceptors.request.use(
      (config) => {
        return config;
      },
      (err) => {
        return err;
      }
    );
    this.instance.interceptors.response.use(
      (res) => {
        return res;
      },
      (err) => {
        const res = err;
        if (res instanceof Error) throw res;
        return res;
      }
    );

    // 实例的拦截器
    this.instance.interceptors.request.use(config.interceptors?.requestInterceptor, config.interceptors?.requestInterceptorCatch);
    this.instance.interceptors.response.use(config.interceptors?.responseInterceptor, config.interceptors?.responseInterceptorCatch);
  }

  request<T = any>(config: HFRequestConfig<T>) {
    if (config.interceptors?.requestInterceptor) {
      config = config.interceptors.requestInterceptor(config);
    }
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.responseInterceptor) {
            res = config.interceptors.responseInterceptor(res);
          }
          resolve(res);
        })
        .catch((err) => {
          if (config.interceptors?.responseInterceptorCatch) {
            err = config.interceptors.responseInterceptorCatch(err);
          }
          reject(err);
        });
    });
  }

  get<T = any>(config: HFRequestConfig<resType<T>>) {
    return this.request<resType<T>>({ ...config, method: "GET" });
  }

  post<T = any>(config: HFRequestConfig<resType<T>>) {
    const obj = {
      ...config,
      method: "POST" as Method,
    };
    return this.request<resType<T>>(obj);
  }

  delete<T = any>(config: HFRequestConfig<resType<T>>) {
    return this.request<resType<T>>({ ...config, method: "DELETE" });
  }

  put<T = any>(config: HFRequestConfig<resType<T>>) {
    const obj = {
      ...config,
      method: "PUT" as Method,
    };
    return this.request<resType<T>>(obj);
  }
}

export default HFRequest;
